package com.softwareengineering.trafficapplicationv2;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;

/**
 * This file is part of the Traffic Simulation Application.
 * The Traffic Simulation Application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The Traffic Simulation Application is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with the Traffic Simulation Application.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @file GraphicsUtil.java
 * @author David Black, Chris Nelson, and Garrett Stibbs, (c) December 03, 2012
 * @description Contains static methods for commonly utilized graphics
 *              operations.
 * 
 */

public class GraphicsUtil {

	//	######################
	//		java.awt.Color
	//	######################
	
	// java.awt.Color.FACTOR
	private static final double FACTOR = 0.7;

	// java.awt.Color.brighter: returns brighter version of input color
	public static int brighter(int color) {
		int r = Color.red(color);	// get red component
		int g = Color.green(color);	// get green component
		int b = Color.blue(color);	// get blue component

		/*
		 * From 2D group: 1. black.brighter() should return grey 2. applying
		 * brighter to blue will always return blue, brighter 3. non pure color
		 * (non zero rgb) will eventually return white
		 */

		int i = (int) (1.0 / (1.0 - FACTOR));
		
		if (r == 0 && g == 0 && b == 0) {	// input color = black
			return Color.rgb(i, i, i);	// return gray
		}

		if (r > 0 && r < i) r = i;	// brighten red component if applicable
		if (g > 0 && g < i) g = i;	// brighten green component if applicable
		if (b > 0 && b < i) b = i;	// brighten blue component if applicable

		// return brighter color with valid components (i.e. r <= 255, g <= 255, b <= 255)
		return Color.rgb(Math.min((int) (r / FACTOR), 255),
				Math.min((int) (g / FACTOR), 255),
				Math.min((int) (b / FACTOR), 255));
	}

	// java.awt.Color.darker: returns darker version of input color
	public static int darker(int color) {
		// return darker color with valid components (i.e. r >= 0, g >= 0, b >= 0)
		return Color.rgb(Math.max((int) (Color.red(color) * FACTOR), 0),
				Math.max((int) (Color.green(color) * FACTOR), 0),
				Math.max((int) (Color.blue(color) * FACTOR), 0));
	}
	
	// java.awt.Color.HSBtoRGB: returns RGB color int with the indicated hue, saturation, brightness
	public static int HSBtoRGB(float hue, float saturation, float brightness) {
		int r = 0, g = 0, b = 0;	// initialize red, green, blue components
		
		if (saturation == 0) {	// if saturation is 0
			r = g = b = (int) (brightness * 255.0f + 0.5f);	// red, green, blue components equal (i.e. grayscale)
		} else {	// if saturation not equal to 0
			// perform color conversion calculations
			float h = (hue - (float) Math.floor(hue)) * 6.0f;
			float f = h - (float) java.lang.Math.floor(h);
			float p = brightness * (1.0f - saturation);
			float q = brightness * (1.0f - saturation * f);
			float t = brightness * (1.0f - (saturation * (1.0f - f)));
			
			//set red, green, blue components according to h
			switch ((int) h) {
			case 0:
				r = (int) (brightness * 255.0f + 0.5f);
				g = (int) (t * 255.0f + 0.5f);
				b = (int) (p * 255.0f + 0.5f);
				break;
			case 1:
				r = (int) (q * 255.0f + 0.5f);
				g = (int) (brightness * 255.0f + 0.5f);
				b = (int) (p * 255.0f + 0.5f);
				break;
			case 2:
				r = (int) (p * 255.0f + 0.5f);
				g = (int) (brightness * 255.0f + 0.5f);
				b = (int) (t * 255.0f + 0.5f);
				break;
			case 3:
				r = (int) (p * 255.0f + 0.5f);
				g = (int) (q * 255.0f + 0.5f);
				b = (int) (brightness * 255.0f + 0.5f);
				break;
			case 4:
				r = (int) (t * 255.0f + 0.5f);
				g = (int) (p * 255.0f + 0.5f);
				b = (int) (brightness * 255.0f + 0.5f);
				break;
			case 5:
				r = (int) (brightness * 255.0f + 0.5f);
				g = (int) (p * 255.0f + 0.5f);
				b = (int) (q * 255.0f + 0.5f);
				break;
			}
		}
		
		// return color int of format 0xAARRGGBB
		return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
	}

	//	####################################
	//		GraphicsUtil Drawing Methods
	//	####################################
	
	// draws a single line on the input canvas between input end points and drawn in input color
	public static void drawLine(Canvas c, int x1, int y1, int x2, int y2,
			int color) {
		Paint paint = new Paint();	// create Paint object for painting
		paint.setStyle(Style.STROKE);	// set style to stroke for drawing lines
		paint.setColor(color);	// set paint color to desired color

		Path path = new Path();	// create new Path
		path.moveTo(x1, y1);	// move to desired start point
		path.lineTo(x2, y2);	// connect path to desired end point

		c.drawPath(path, paint);	// draw line to canvas using paint
	}

	// draws a stroked (non-filled) polygon on the input canvas with input vertices and drawn in input color
	public static void drawPolygon(Canvas c, int[] x, int[] y, int vertices,
			int color) {
		Paint paint = new Paint();	// create Paint object for painting
		paint.setStyle(Style.STROKE);	// set style to stroke for drawing lines
		paint.setColor(color);	// set paint color to desired color

		Path path = new Path();	// create new Path
		path.moveTo(x[0], y[0]);	// move to first vertex

		for (int i = 1; i < vertices; i++)	// for all other vertices
			path.lineTo(x[i], y[i]);	// connect path from previous vertex to current vertex

		path.lineTo(x[0], y[0]);	// close polygon

		c.drawPath(path, paint);	// draw polygon to canvas using paint
	}

	// draws a filled oval on the input canvas with input location and size and drawn in input color
	public static void fillOval(Canvas c, int left, int top, int width,
			int height, int color) {
		Paint paint = new Paint();	// create Paint object for painting
		paint.setStyle(Style.FILL);	// set style to fill for filling oval
		paint.setColor(color);	// set paint color to desired color

		c.drawOval(new RectF(left, top, left + width, top + height), paint);	// draw oval to canvas using paint with desired bounds
	}

	// draws a filled polygon on the input canvas with input vertices and drawn in input color
	public static void fillPolygon(Canvas c, int[] x, int[] y, int vertices,
			int color) {
		Paint paint = new Paint();	// create Paint object for painting
		paint.setStyle(Style.FILL);	// set style to fill for filling polygon
		paint.setColor(color);	// set paint color to desired color

		Path path = new Path();	// create new Path
		path.moveTo(x[0], y[0]);	// move to first vertex

		for (int i = 1; i < vertices; i++)	// for all other vertices
			path.lineTo(x[i], y[i]);	// connect path from previous vertex to current vertex

		path.lineTo(x[0], y[0]);	// close polygon

		c.drawPath(path, paint);	// draw polygon to canvas using paint
	}

	// draws a filled rectangle on the input canvas with input location and size and drawn in input color
	public static void fillRect(Canvas c, int left, int top, int width,
			int height, int color) {
		Paint paint = new Paint();	// create Paint object for painting
		paint.setStyle(Style.FILL);	// set style to fill for filling rectangle
		paint.setColor(color);	// set paint color to desired color

		c.drawRect(left, top, left + width, top + height, paint);	// draw rectangle to canvas using paint with desired bounds
	}

}
